package com.sibbay.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedList;

import android.util.Log;

/* 
 * structure of file
Route 901 - Northbnd - Weekday
TRSA STN 	Santa Teresa Light Rail Sta.   
SNEL STN 	Snell Light Rail Station        

TRSA STN 	SNEL STN 	OHLN CHYN	CAPT STN 	TAMN STN 	CONV CTR 	SANT CLRA	LVE  CLRA	CIVC CTR 	MTRO STA.	TASM STA.	LVE  TASM	BAY  PT. 	GRT. MALL	HOST STA.	PENT T.C.	ALUM ROCK	
4:16A	4:21A	4:25A	4:28A	4:33A	4:39A	4:44A		4:51A	4:56A	5:05A			5:14A	5:20A	5:24A	5:30A	
4:51A	4:56A	5:00A	5:03A	5:08A	5:14A	5:19A		5:26A	5:31A	5:40A	5:41A		5:50A	5:56A	6:00A	6:06A	
 */
public final class Parser {
	private static final String TAG = "VTA Parser";

	private String[] mStationList;
	private String[][] mTimeTable;	// 1 - by station, 2 - by time
	private ParamByRef<Integer> mMaxTimeTabletSize = new ParamByRef<Integer>();

	public void parse(final File file) throws IOException {
		parse(new FileReader(file));
	}
	
	public void parse(final Reader input) throws IOException {
		try {
			final BufferedReader rd = new BufferedReader(input);
			// format: Route 902 - Northbnd - Weekday
			rd.mark(1000);
			final String header = parseHeader(rd);
			if (!header.substring(0, 6).equals("Route "))
				rd.reset();
			
			mStationList = parseStationList(rd);
			@SuppressWarnings("unused")
			final String[] timeHeader = parseTimeHeader(rd, mStationList.length);
			mTimeTable = parseTimeTable(rd, mStationList.length, mMaxTimeTabletSize);
		} finally {
			input.close();
		}
	}
	
	// use after parsing
	
	public boolean isValid() {
		return 	mStationList != null &&
				mTimeTable != null;
	}

	public String[] getStationList() {
		return mStationList;
	}
	
	public String[][] getTimeTable() { 
		return mTimeTable;
	}
	
	public int getMaxTimeTabletSize() {
		return mMaxTimeTabletSize.get();
	}
	
	///
	
	private static String parseHeader(final BufferedReader rd) throws IOException {
		return rd.readLine();
	}

	private static String[] parseStationList(final BufferedReader rd) throws IOException {
		final ArrayList<String> ret = new ArrayList<String>();
		String line;
		while ((line = rd.readLine()) != null) {
//			Log.d(TAG, "line:" + line);
			if (line.length() <= 0) {
				return ret.toArray(new String[ret.size()]);
			}
			final String[] arr = split(line, 2);
			if (arr == null) {
				return null;
			}
			ret.add(doCorrection(arr[1].trim()));
		}
		return null;
	}
	
	private static String[] parseTimeHeader(final BufferedReader rd, int size) throws IOException {
		final String line = rd.readLine().trim();
		final String[] ret = split(line, size);
		return ret;
	}

	private static String[][] parseTimeTable(final BufferedReader rd, int size, final ParamByRef<Integer> max) throws IOException {
		final LinkedList<String[]> arr = new LinkedList<String[]>(); 
		String line;
		while ((line = rd.readLine()) != null) {
			final String[] time = split(line, size);	// have extra \t at end
			if (time == null) {
				return null;
			}
			arr.add(time);
		}
		// repack into stations , skip empty time
		int maxSize = 0;
		final String[][] ret = new String[size][];
		for (int i = 0; i < ret.length; ++i) {
			final ArrayList<String> t = new ArrayList<String>(arr.size());
			int z = 0;
			for (int j = 0; j < arr.size(); ++j) {
				final String s = arr.get(j)[i];
				if (s != null && s.length() > 0) {
					t.add(s);
					z++;
				}
			}
			final String[] a = new String[z];
			ret[i] = t.toArray(a);
			maxSize = Math.max(maxSize, z);
		}
		max.set(maxSize);
		return ret;
	}
	
	/**
	 * split string by "\t" with expected size
	 * string is "str1 \t str2 \t str3 "
	 * @param str
	 * @param size
	 * @return
	 */
	private static String[] split(final String str, int size) {
		final String[] ret = new String[size];
		int start = 0;
		int i;
		for (i = 0; i < size - 1; ++i) {
			final int pos = str.indexOf('\t', start);
			if (pos < 0) {
				break;
			}
			ret[i] = trimTime(str.substring(start, pos));
			start = pos + 1;
		}
		ret[i] = trimTime(str.substring(start, str.length()));
		++i;
		if (i != size) {
			Log.w(TAG, "split - doesn't have " + size + " tokens: " + str);
			return null;
		}
		return ret;
	}
	
	// return 00:00A format
	
	private static String trimTime(final String str) {
		final String ret = str.trim();
		if (str.length() <= 0)
			return null;
		
		if (ret.length() == 5)
			return "0" + ret;
		
		return ret;
	}
	
	private static String doCorrection(final String str) {
		String ret = str.replace("&amp;", "&");
		ret = ret.replace("Sta.", "Station");
		return ret;
	}
}
